package org.diretto.api.client.main.storage.upload;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import org.diretto.api.client.base.data.UploadInfo;
import org.diretto.api.client.session.UserSession;
import org.diretto.api.client.user.UserFactory;
import org.restlet.Client;
import org.restlet.resource.ClientResource;
/**
* This class is the implementation class of the {@link UploadProcess}
* interface.
*
* @author Tobias Schlecht
*/
final class UploadProcessImpl implements UploadProcess, Future<UploadReport>, Runnable
{
private final UploadManager uploadManager;
private final UserSession userSession;
private final UploadInfo uploadInfo;
private final UploadHttpEntity uploadHttpEntity;
private final String uploadURL;
private final DefaultHttpClient httpClient;
private final Client restletClient;
private final CountDownLatch countDownLatch = new CountDownLatch(1);
private volatile boolean done = false;
private volatile UploadState uploadState = UploadState.INIT;
private volatile long uploadProcessStartTime = 0L;
private volatile long uploadProcessEndTime = 0L;
private volatile long uploadingEndTime = 0L;
private volatile UploadReport uploadReport = null;
/**
* Constructs an object of the {@link UploadProcess} interface.
*
* @param uploadManager The corresponding {@code UploadManager}
* @param userSession The corresponding {@code UserSession}
* @param uploadInfo The {@code UploadInfo} object
* @param uploadHttpEntity The {@code UploadHttpEntity}
*/
UploadProcessImpl(UploadManager uploadManager, UserSession userSession, UploadInfo uploadInfo, UploadHttpEntity uploadHttpEntity)
{
this.uploadManager = uploadManager;
this.userSession = userSession;
this.uploadInfo = uploadInfo;
this.uploadHttpEntity = uploadHttpEntity;
uploadURL = uploadInfo.getTarget().toExternalForm();
httpClient = uploadManager.getHttpClient(userSession);
restletClient = uploadManager.getRestletClient();
}
/**
* Returns the <i>Apache</i> {@link DefaultHttpClient}.
*
* @return The <i>Apache</i> {@code DefaultHttpClient}
*/
DefaultHttpClient getHttpClient()
{
return httpClient;
}
@Override
public boolean cancel(boolean mayInterruptIfRunning)
{
throw new UnsupportedOperationException();
}
@Override
public UploadReport get() throws InterruptedException, ExecutionException
{
countDownLatch.await();
return uploadReport;
}
@Override
public UploadReport get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
countDownLatch.await(timeout, unit);
return uploadReport;
}
@Override
public boolean isCancelled()
{
return false;
}
@Override
public boolean isDone()
{
return done;
}
@Override
public void run()
{
try
{
uploadProcessStartTime = System.nanoTime();
HttpPut httpPut = new HttpPut(uploadURL);
httpPut.setEntity(uploadHttpEntity);
uploadState = UploadState.UPLOADING;
HttpResponse httpResponse = httpClient.execute(httpPut);
uploadingEndTime = System.nanoTime();
System.out.println("[StorageService UploadProcessImpl] " + uploadURL);
if(httpResponse.getStatusLine().getStatusCode() != 201 && httpResponse.getStatusLine().getStatusCode() != 202)
{
System.err.println("[StorageService UploadProcessImpl] " + httpResponse.getStatusLine().getStatusCode());
return;
}
uploadState = UploadState.PUBLISHING;
HttpEntity httpResponseEntity = httpResponse.getEntity();
String successToken = "";
JsonFactory jsonFactory = new JsonFactory();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
httpResponseEntity.writeTo(byteArrayOutputStream);
byteArrayOutputStream.flush();
JsonParser jsonParser = jsonFactory.createJsonParser(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
jsonParser.nextToken();
while(jsonParser.nextToken() != JsonToken.END_OBJECT)
{
String fieldName = jsonParser.getCurrentName();
jsonParser.nextToken();
if("successToken".equals(fieldName))
{
successToken = jsonParser.getText();
}
else
{
return;
}
}
jsonParser.close();
if(successToken.equals(""))
{
return;
}
ClientResource clientResource = new ClientResource(uploadInfo.getAttachmentID().getUniqueResourceURL().toExternalForm() + "/lock?token=" + successToken);
clientResource.setNext(restletClient);
UserFactory.authenticateClientResource(userSession.getUser(), clientResource);
clientResource.delete();
System.out.println("[StorageService UploadProcessImpl] " + uploadInfo.getAttachmentID().getUniqueResourceURL().toExternalForm() + "/lock?token=" + successToken);
if(clientResource.getStatus().getCode() != 204 && clientResource.getStatus().getCode() != 200 && clientResource.getStatus().getCode() != 202)
{
System.err.println("[StorageService UploadProcessImpl] " + clientResource.getStatus().getCode());
return;
}
uploadProcessEndTime = System.nanoTime();
uploadReport = new UploadReport(uploadInfo, uploadProcessStartTime, uploadProcessEndTime, uploadProcessStartTime, uploadingEndTime);
uploadState = UploadState.FINISHED;
uploadHttpEntity.consumeContent();
httpResponseEntity.consumeContent();
}
catch(ClientProtocolException e)
{
return;
}
catch(IOException e)
{
return;
}
finally
{
if(uploadingEndTime == 0L)
{
uploadingEndTime = System.nanoTime();
}
if(uploadProcessEndTime == 0L)
{
uploadProcessEndTime = System.nanoTime();
}
if(uploadState != UploadState.FINISHED)
{
uploadState = UploadState.ABORTED;
}
uploadManager.finish(this);
done = true;
countDownLatch.countDown();
}
}
@Override
public synchronized int getProgress()
{
switch(getCurrentState())
{
case INIT:
return 0;
case UPLOADING:
return (int) ((double) (uploadHttpEntity.getByteCount() * 95L) / (double) uploadHttpEntity.getContentLength());
case PUBLISHING:
return 95;
case FINISHED:
return 100;
case ABORTED:
return 100;
default:
return 0;
}
}
@Override
public synchronized long getElapsedTime()
{
if(uploadProcessStartTime == 0L)
{
return 0L;
}
else if(uploadProcessEndTime != 0L)
{
return Math.round(((double) (uploadProcessEndTime - uploadProcessStartTime)) / 1000000.0d);
}
return Math.round(((double) (System.nanoTime() - uploadProcessStartTime)) / 1000000.0d);
}
@Override
public synchronized UploadState getCurrentState()
{
return uploadState;
}
}